package orders

import (
	"context"
	"errors"
	"fmt"
	"github.com/google/uuid"
	"github.com/shopspring/decimal"
	"github.com/zeromicro/go-zero/core/logx"
	"gorm.io/gorm"
	"insighttracking/apps/customer/auth"
	"insighttracking/apps/customer/internal/svc"
	"insighttracking/apps/customer/internal/types"
	"insighttracking/common/enum"
	"insighttracking/common/utils"
	"insighttracking/query/dao"
	"insighttracking/query/service"
	"net/http"
	"os"
	"strings"
	"time"
)

type ApiLogic struct {
	logx.Logger
	ctx     context.Context
	svcCtx  *svc.ServiceContext
	Request *http.Request
}

func NewApiLogic(ctx context.Context, svcCtx *svc.ServiceContext, request *http.Request) *ApiLogic {
	hostname, _ := os.Hostname()
	return &ApiLogic{
		Logger: logx.WithContext(ctx).WithCallerSkip(0).WithFields(
			logx.Field("Log_UUID", uuid.New().String()),
			logx.Field("hostname", hostname)),
		ctx:     ctx,
		svcCtx:  svcCtx,
		Request: request,
	}
}

func (l *ApiLogic) ConfirmDeliveryGoodsApi(req *types.ConfirmDeliveryGoodsReq) (resp string, err error) {
	ordersEntityList, err := dao.OrdersEntity.WithContext(l.ctx).Where(dao.OrdersEntity.ID.In(req.IdList...)).Find()
	if err != nil {
		return "", err
	}
	if len(ordersEntityList) == 0 {
		return "", errors.New("没有可操作的数据")
	}
	for _, orderEntity := range ordersEntityList {
		if orderEntity.Status != enum.OrdersAlreadyShippedEnum {
			return "", errors.New("当前包括未发货,不能直接收货")
		}
	}
	if _, err = dao.OrdersEntity.WithContext(l.ctx).Where(dao.OrdersEntity.ID.In(req.IdList...)).UpdateSimple(
		dao.OrdersEntity.Status.Value(enum.OrdersCompletedEnum),
	); err != nil {
		logx.Errorf("收货失败:%v", err)
		return "", errors.New("收货失败")
	}
	return "收货成功", nil
}

func (l *ApiLogic) DeliveryListApi(req *types.IdReq) (resp *types.DeliveryListResp, err error) {
	resp = &types.DeliveryListResp{}
	orderEntity, err := service.OrdersService.GetByIdApi(l.ctx, req.Id)
	if err != nil {
		return
	}
	resp.SendGoodsDate = utils.TimestampToString(orderEntity.SendGoodsDate)
	resp.OrderNo = orderEntity.OrderNo
	resp.CreatedAt = utils.TimestampToString(orderEntity.CreatedAt)
	orderDetailList := make([]*types.DeliveryDetailList, 0)
	orderDetailEntities, err := service.OrdersDetailService.GetByOrderIdListApi(l.ctx, []int64{req.Id})
	if err != nil {
		return
	}

	totalMap := make(map[int64]*types.DeliveryTotalList)
	orderDetail := &types.DeliveryDetailList{}
	for _, orderDetailEntity := range orderDetailEntities {
		if orderDetailEntity.SpuID != 0 {
			orderDetail.SpuCount = orderDetailEntity.SpuCount
			orderDetail.SpuID = orderDetailEntity.SpuID
			orderDetail.DishID = 0
			orderDetail.DeliveryCount = orderDetailEntity.SpuCount.String() + orderDetailEntity.SnapshotUnit
			orderDetail.SpuName = orderDetailEntity.SnapshotName
			orderDetail.UnitName = orderDetailEntity.SnapshotUnit
			orderDetail.Ratio = ""
			if _, ok := totalMap[orderDetailEntity.SpuID]; !ok {
				totalMap[orderDetailEntity.SpuID] = &types.DeliveryTotalList{
					SpuID:         orderDetailEntity.SpuID,
					SpuName:       orderDetailEntity.SnapshotName,
					DeliveryCount: orderDetailEntity.SpuCount,
					UnitName:      orderDetailEntity.SnapshotUnit,
				}
			} else {
				totalMap[orderDetailEntity.SpuID].DeliveryCount = totalMap[orderDetailEntity.SpuID].DeliveryCount.Add(orderDetailEntity.SpuCount)
			}
			orderDetailList = append(orderDetailList, orderDetail)
		} else {
			continue
		}
	}

	for _, orderDetailEntity := range orderDetailList {
		if orderDetailEntity.DishID != 0 {
			dishID := orderDetailEntity.DishID
			dishRatio, err := service.DishService.GetSpuRatioApi(l.ctx, dishID)
			dishEntity, err := service.DishService.GetByIDApi(l.ctx, dishID)
			if err != nil {
				return nil, err
			}
			orderDetail.SpuID = 0
			orderDetail.DishID = dishID
			orderDetail.DishName = dishEntity.Name
			orderDetail.UnitName = "斤"
			orderDetail.SpuCount = orderDetailEntity.SpuCount
			var spuName, ratio, deliveryCount []string
			for _, item := range dishRatio {
				spuName = append(spuName, item.Name)
				ratio = append(ratio, fmt.Sprintf("%.2f%%", float64(item.Percent)*0.01))
				deliveryCount = append(deliveryCount, orderDetailEntity.SpuCount.Mul(decimal.New(item.Percent, 2)).Div(decimal.New(10000, 2)).String()+item.UnitName)
				if _, ok := totalMap[item.SpuID]; !ok {
					totalMap[orderDetailEntity.SpuID] = &types.DeliveryTotalList{
						SpuID:         item.SpuID,
						SpuName:       item.Name,
						DeliveryCount: orderDetailEntity.SpuCount.Mul(decimal.New(item.Percent, 2)).Div(decimal.New(10000, 2)),
						UnitName:      item.UnitName,
					}
				} else {
					totalMap[orderDetailEntity.SpuID].DeliveryCount = totalMap[orderDetailEntity.SpuID].DeliveryCount.Add(orderDetailEntity.SpuCount.Mul(decimal.New(item.Percent, 2)).Div(decimal.New(10000, 2)))
				}
			}
			orderDetail.SpuName = strings.Join(spuName, ",")
			orderDetail.Ratio = strings.Join(ratio, ",")
			orderDetail.DeliveryCount = strings.Join(deliveryCount, ",")
			orderDetailList = append(orderDetailList, orderDetail)
		} else {
			continue
		}
	}

	resp.OrderDetailList = orderDetailList
	totalList := make([]*types.DeliveryTotalList, 0)
	for _, v := range totalMap {
		totalList = append(totalList, v)
	}
	resp.TotalList = totalList
	return
}

func (l *ApiLogic) PackageDeliveryApi(req *types.PackageDeliveryReq) (resp types.PackageDeliveryResp, err error) {
	resp = types.PackageDeliveryResp{}
	entity, err := service.ProductionSortingService.GetByBatchNumber(l.ctx, req.ProductionBatchNumber)
	if err != nil {
		return resp, errors.New("生产批号有误")
	}
	if entity.OrdersSpuID == 0 {
		return resp, errors.New("该包裹未出库")
	}
	if entity.Status == enum.ProductionSortingReceived {
		return resp, errors.New("该包裹已收货")
	}
	ordersSpu, err := service.OrdersSpuService.GetByIDApi(l.ctx, entity.OrdersSpuID)
	if err != nil {
		return resp, errors.New("生产批号关联的订单号有误")
	}

	orders, err := service.OrdersService.GetByIdApi(l.ctx, ordersSpu.OrdersID)
	accountInfo, err := auth.GetAccountInfo(l.svcCtx, l.Request)
	if err != nil {
		return
	}
	if orders.CustomerID != accountInfo.CustomerId {
		return resp, errors.New("该包裹不属于当前门店")
	}
	if orders.EnterpriseID != accountInfo.EnterpriseId {
		return resp, errors.New("该包裹不属于当前客户")
	}

	tx := dao.Use(l.svcCtx.MysqlDb).Begin()

	_, err = tx.ProductionSortingEntity.WithContext(l.ctx).Where(dao.ProductionSortingEntity.ProductionBatchNumber.Eq(entity.ProductionBatchNumber)).
		UpdateSimple(
			dao.ProductionSortingEntity.Status.Value(enum.ProductionSortingReceived),
			dao.ProductionSortingEntity.ReceiveTime.Value(time.Now()),
			dao.ProductionSortingEntity.ReceiveType.Value(req.Type),
			dao.ProductionSortingEntity.ReceiverID.Value(accountInfo.AccountId),
			dao.ProductionSortingEntity.Receiver.Value(accountInfo.Username),
		)
	_ = tx.Commit()
	resp.ID = entity.OrdersSpuID
	resp.OrdersID = ordersSpu.OrdersID
	return
}

func (l *ApiLogic) GetPackageApi(req *types.IdReq) (resp *types.GetPackageResp, err error) {
	resp = &types.GetPackageResp{}
	entities, err := service.ProductionSortingService.GetPackedList(l.ctx, req.Id)
	if err != nil {
		return
	}
	ordersSpu, err := service.OrdersSpuService.GetByIDApi(l.ctx, req.Id)
	if err != nil {
		return
	}
	orders, err := service.OrdersService.GetByIdApi(l.ctx, ordersSpu.OrdersID)
	if err != nil {
		return
	}
	resp.SpuName = ordersSpu.SpuName
	resp.UnitName = ordersSpu.UnitName
	resp.OrdersNo = orders.OrderNo
	resp.ProductImageURL = ordersSpu.ProductImageURL
	unreceivedPackageList := make([]*types.UnreceivedPackageList, 0)
	receivedRecordList := make([]*types.ReceivedRecordList, 0)
	for _, entity := range entities {
		if entity.Status == enum.ProductionSortingReceived {
			receivedRecordList = append(receivedRecordList, &types.ReceivedRecordList{
				CreatedAt:             utils.TimestampToString(entity.CreatedAt),
				Operator:              entity.Receiver,
				ProductionBatchNumber: entity.ProductionBatchNumber,
				Type:                  entity.ReceiveType,
				Weight:                entity.Weight.InexactFloat64(),
			})
		}
		if entity.Status != enum.ProductionSortingReceived {
			unreceivedPackageList = append(unreceivedPackageList, &types.UnreceivedPackageList{
				Status:                entity.Status,
				ProductionBatchNumber: entity.ProductionBatchNumber,
				Weight:                entity.Weight.InexactFloat64(),
			})
		}
	}
	resp.UnreceivedPackageList = unreceivedPackageList
	resp.ReceivedRecordList = receivedRecordList
	return
}

func (l *ApiLogic) ScanInfoApi(req *types.ProductionBatchNumberForm) (resp *types.ProductionPlanLabelResp, err error) {
	resp = &types.ProductionPlanLabelResp{}
	entity, err := service.ProductionSortingService.GetByBatchNumber(l.ctx, req.ProductionBatchNumber)
	if err != nil {
		return
	}
	spu, err := service.SpuService.GetSpuDetailByIdApi(l.ctx, entity.SpuID)
	if err != nil {
		return
	}
	ordersSpu, err := service.OrdersSpuService.GetByIDApi(l.ctx, entity.OrdersSpuID)
	if err != nil {
		return
	}
	orders, err := service.OrdersService.GetByIdApi(l.ctx, ordersSpu.OrdersID)
	if err != nil {
		return
	}
	resp = &types.ProductionPlanLabelResp{
		OrdersNo:              orders.OrderNo,
		ProduceDate:           entity.CreatedAt.Format("2006-01-02"),
		ProductionBatchNumber: entity.ProductionBatchNumber,
		SpuName:               spu.Name,
		UnitName:              spu.UnitName,
		ProductImageURL:       spu.ProductImageURL,
		Weight:                entity.Weight.InexactFloat64(),
		Status:                entity.Status,
	}
	return
}

func (l *ApiLogic) GoodsDeliveryApi(req *types.GoodsReceiveReq) (resp string, err error) {
	ordersSpu, err := service.OrdersSpuService.GetByIDApi(l.ctx, req.ID)
	if err != nil {
		return "", errors.New("订单号有误")
	}

	tx := dao.Use(l.svcCtx.MysqlDb).Begin()
	modifyStatus := map[string]any{
		"receive_status": 20,
		"receive_time":   time.Now(),
	}
	err = service.OrdersSpuService.ModifyByIDApi(l.ctx, tx, req.ID, modifyStatus)
	if err != nil {
		if err = tx.Rollback(); err != nil {
			return "", errors.New("操作失败")
		}
	}
	_ = tx.Commit()

	ordersID := ordersSpu.OrdersID
	// 查询是否全部收货
	ordersSpus, err := service.OrdersSpuService.GetUnReceivedListByOrdersIDApi(l.ctx, ordersID)
	if err != nil && !errors.Is(err, gorm.ErrRecordNotFound) {
		return
	}

	if errors.Is(err, gorm.ErrRecordNotFound) || len(ordersSpus) == 0 {
		if err = service.OrdersService.ModifyStatusByIdApi(l.ctx, nil, []int64{ordersID}, enum.OrdersCompletedEnum); err != nil {
			return "", errors.New("修改订单状态失败")
		}
	}
	return
}
